# -*- coding: utf-8 -*-
#
# Copyright (C) 2011  Benjamin Heil
#
# This file is part of Feedmail.
#
# Feedmail is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import feedparser
import socket
import urllib2

from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.template.loader import render_to_string
from django.contrib.auth.decorators import login_required
from django.utils import simplejson
from django.conf import settings
from django.utils.html import escape
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

from feedmanager.models import FeedItem, FeedAbo, FeedData, FeedError
from feedmanager.parser import getEntryFingerprint, getEntryFingerprint_MD5

_FEEDMAIL_JSON_VERSION = '0.1'

def _getJSONData(request, value):
    data = {'type': settings.SITE_FULL_NAME,
            'version': _FEEDMAIL_JSON_VERSION,
            'data': value.strip()}
    return simplejson.dumps(data)

@login_required
def feedmanager_get_feed_table(request):
    abo_list = FeedAbo.objects.filter(user=request.user)
    feed_list = []
    for abo in abo_list:
        feed_list.append({
            'name': abo.feed.name,
            'id': abo.feed.id,
            'url': abo.feed.url,
            'is_gone': abo.feed.is_gone
        })
    feed_list.sort(key=lambda feed: feed['name'].lower())
    data = render_to_string('feedmanager/feed_table.html', {'feed_list': feed_list},
                              context_instance=RequestContext(request))
    return HttpResponse(_getJSONData(request, data),
                        mimetype="application/json")

@login_required
def feedmanager_remove_feed(request):
    try:
        id = request.GET.get('id')
        feed = FeedItem.objects.get(id=id)
        abo = FeedAbo.objects.get(user=request.user, feed=feed)
    except:
        return HttpResponseForbidden()
    abo.delete()
    abos_left = FeedAbo.objects.filter(feed=feed)
    if not abos_left:        
        # This was the last abo for this feed, so remove the feed completely
        # But first remove all errors associated with this feed
        errors = FeedError.objects.filter(feed=feed)
        errors.delete()
        feed.delete()
    return HttpResponse(_getJSONData(request, 'success'),
                        mimetype="application/json")

@login_required
def feedmanager_dashboard(request, is_dashboard=True):
    return render_to_response('feedmanager/dashboard.html',
                              {'is_dashboard': is_dashboard},
                              context_instance=RequestContext(request))

def _check_feed(url):
    r = feedparser.parse(url, agent=settings.FEEDPARSER_USER_AGENT)
    http_status = r.get('status', 200)
    http_headers = r.get('headers', {'content-type': 'application/rss+xml', 'content-length':'1'})
    exc_type = r.get("bozo_exception", Exception()).__class__
    if http_status != 304 and http_status != 302 and not r.get('version', ''):
        socket_errors = []
        for e in ['error', 'gaierror']:
            if hasattr(socket, e):
                socket_errors.append(getattr(socket, e))
        if http_status == 410:
            return u'[410] An dieser Adresse existiert nichts mehr', r
        elif http_status == 404:
            return u'[404] Diese URL ist ungültig', r
        elif http_status not in [200, 302]:
            return u'[%s] Unbekannter Fehler' % http_status, r
        elif http_headers.get('content-type', 'rss').find('html') != -1:
            return u'Sieht nach HTML aus! Das ist die Adresse einer Webseite, keines Feeds.', r
        elif http_headers.get('content-length', '1') == '0':
            return u'Leere Seite', r
        elif hasattr(socket, 'timeout') and exc_type == socket.timeout:
            return u'Feed brauchte zu lange zum Antworten', r
        elif exc_type == IOError:
            return r.bozo_exception, r
        elif hasattr(feedparser, 'zlib') and exc_type == feedparser.zlib.error:
            return u'Fehlerhafte Kompression des Feeds', r
        elif exc_type in socket_errors:
            return r.bozo_exception.args[1], r
        elif exc_type == urllib2.URLError:
            if r.bozo_exception.reason.__class__ in socket_errors:
                exc_reason = r.bozo_exception.reason.args[1]
            else:
                exc_reason = r.bozo_exception.reason
            return exc_reason, r
        elif exc_type == AttributeError:
            return r.bozo_exception, r
        elif r.bozo:
            return u'Kann diese Adresse nicht verarbeiten', r
    return '', r

def _save_existing_fingerprints(feed_result):
    for entry in feed_result:
        fingerprint = entry.get('id', getEntryFingerprint(entry))
        fingerprint_md5 = getEntryFingerprint_MD5(entry, fingerprint=fingerprint)
        try:
            f = FeedData.objects.get(fingerprint=fingerprint,
                                     fingerprint_md5=fingerprint_md5)
        except FeedData.DoesNotExist:
            data = FeedData(fingerprint=fingerprint,
                            fingerprint_md5=fingerprint_md5)
            data.save()

@login_required
def feedmanager_add_feed(request):
    if not request.method == "POST":
        return HttpResponseForbidden()
    url = request.POST.get('url', '')
    check_result, feed_result = _check_feed(url)
    if check_result:
        msg = u'Dies ist kein gültiger RSS- oder Atom-Feed und kann nicht abonniert werden. Folgender Fehler trat auf:<br /><br /><strong>%s</strong>' % check_result
        return HttpResponse(_getJSONData(request, msg),
                            mimetype="application/json")
    try:
        # Feed existiert schon (muss unique sein), aber wir brauchen die ID des Feeds
        feed = FeedItem.objects.get(url=url)
        feed_result = None
    except FeedItem.DoesNotExist:
        feed = FeedItem(url=url)
        feed.save()
    try:
        f = FeedAbo.objects.get(user=request.user, feed=feed)
        return HttpResponse(_getJSONData(request, 'Du hast diesen Feed schon abonniert!'),
                            mimetype="application/json")
    except FeedAbo.DoesNotExist:
        pass
    abo = FeedAbo()
    abo.user = request.user
    abo.feed = feed
    abo.save()
    if feed_result:
        _save_existing_fingerprints(feed_result.entries)
    return HttpResponse(_getJSONData(request, u'Der Feed wurde abonniert! Der Feed lieferte diesen Namen:<br /><br /><strong>%s</strong><br /><br /><i>Beachte, dass Dir nur <strong>zukünftige</strong> Einträge per Mail zugeschickt werden.</i>' % escape(feed.name)),
                        mimetype="application/json")

@login_required
def feedmanager_get_error_table(request):
    feed_list = [abo.feed for abo in FeedAbo.objects.filter(user=request.user)]
    error_list = FeedError.objects.filter(feed__in=feed_list).order_by('-timestamp')    
    paginator = Paginator(error_list, settings.PAGINATION_ITEMS_PER_PAGE)
    page = request.GET.get('page')
    if page:
        try:
            errors = paginator.page(page)
        except PageNotAnInteger:
            errors = paginator.page(1)
        except EmptyPage:
            errors = paginator.page(paginator.num_pages)
    else:
        errors = paginator.page(1)
    data = render_to_string('feedmanager/error_table.html',
                            {'errors': errors},
                            context_instance=RequestContext(request))
    return HttpResponse(_getJSONData(request, data),
                        mimetype="application/json")
        